/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frstat_conn.c                                      */
/*  NOTE      =                                                    */
/*  DATE      = 2015/05/14 by yaohl                                */
/*******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/sysinfo.h>

#include "frcomm.h"
#include "frmem.h"
#include "frlog.h"
#include "frlist.h"
#include "frhash2.h"

#include "frct_comm.h"
#include "frreport_comm.h"
#include "frreport_mng.h"

typedef enum __em_stat_conn_type
{
    FRSTAT_CONN_TYPE_UNKNOWN =0,
    FRSTAT_CONN_TYPE_CONN = 1,
    FRSTAT_CONN_TYPE_REFUSED,
    FRSTAT_CONN_TYPE_RESET,
    FRSTAT_CONN_TYPE_TX,
    FRSTAT_CONN_TYPE_RX,
}Frstat_conn_type;

typedef struct __conns_stat {
    u_int   src_ip;
    u_int   dst_ip;
    u_short dst_port;
    
    unsigned long ul_active;            //当前活跃的总连接数
    unsigned long ul_syn;               //并发连接数
    unsigned long ul_close;             //fin/timeout连接数
    unsigned long ul_refused;           //拒绝连接的次数
    unsigned long ul_reset;             //客户端放弃或连接重置、非正常结束的次数
    unsigned long ul_tx_bytes;
    unsigned long ul_rx_bytes;

    long l_uptime;                      //系统运行时间
} Frconns_stat;

FR_STATIC Frhash_header g_st_hash_stat_conn={0,0,NULL};
FR_STATIC pthread_rwlock_t g_conns_rwlock;

//超过24小时没有通信的数据节点删除
#define FRSTAT_TIMEOUT_SEC        86400

/*******************************************************************************
*  FUNC     :  生成hash用key
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC int __conn_key(u_int ui_src_ip, u_int ui_dst_ip, u_short us_dst_port
                        , char *p_key, unsigned int ui_key_size)
{
    int i_key_len=0;

    if(p_key == NULL || ui_key_size < sizeof(u_short) *2 + sizeof(u_int) *2 )
        return 0;

    memcpy(p_key+i_key_len, &ui_src_ip, sizeof(u_int));
    i_key_len += sizeof(u_int);

    memcpy(p_key+i_key_len, &ui_dst_ip, sizeof(u_int));
    i_key_len += sizeof(u_int);

    memcpy(p_key+i_key_len, &us_dst_port, sizeof(u_short));
    i_key_len += sizeof(u_short);

    return i_key_len;
}

/*******************************************************************************
*  FUNC     :  如果连接数为0，删除
*  ARGS     :  i_l7_proto       l7协议名
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frstat_conns_del(Frlist_node *p_st_node_stat, long l_uptime)
{
    Frconns_stat *p_st_conn_stat=NULL;

    if(p_st_node_stat == NULL)
        return;

    pthread_rwlock_wrlock(&g_conns_rwlock);

    p_st_conn_stat =  (Frconns_stat*)FRLIST_GET_NODE_DATA(p_st_node_stat);
    frhash2_del(&g_st_hash_stat_conn, p_st_node_stat, frlist_node_data_free);

    pthread_rwlock_unlock(&g_conns_rwlock);

    return;
}

/*******************************************************************************
*  FUNC     : 连接信息上报，并删除空节点
*  ARGS     :
*  RTN      :
*  NOTE     : 该函数不能并发调用
*******************************************************************************/
void frstat_conns_report(void)
{
    Frlist_header st_lst_hdr_del, *p_lst_hdr_conn=NULL;
    Frlist_node *p_st_node_stat = NULL, *p_st_node_del=NULL;
    Frconns_stat *p_st_conn_stat=NULL;
    Frreport_data *p_st_report_data=NULL;
    Frreport_body_data *p_st_report_body=NULL;
    int i_loop=0, i_has_report_data = FR_NO, i_total_conn=0;
    struct sysinfo st_info;
    long l_uptime=0;

    p_st_report_data = frreport_data_stat_conn_new();
    if(p_st_report_data == NULL)
        return;

    if(sysinfo(&st_info) == 0)
        l_uptime = st_info.uptime;

    frlist_header_init(&st_lst_hdr_del);
    //没有删除操作，hash表不加锁
    FRHASH_LOOP(i_loop, &g_st_hash_stat_conn, p_lst_hdr_conn)
    {
        if(p_lst_hdr_conn == NULL)
            continue;
        p_st_node_stat = FRLIST_FIRST_NODE(p_lst_hdr_conn);
        while(p_st_node_stat)
        {
            p_st_conn_stat =  (Frconns_stat*)FRLIST_GET_NODE_DATA(p_st_node_stat);
            if(p_st_conn_stat)
            {
                //数据上报
                i_total_conn = p_st_conn_stat->ul_active + p_st_conn_stat->ul_close;
                if(i_total_conn > 0 || p_st_conn_stat->ul_tx_bytes || p_st_conn_stat->ul_rx_bytes)
                {
                    p_st_report_body = frreport_body_new_stat_conn(p_st_conn_stat->src_ip
                                                                 , p_st_conn_stat->dst_ip
                                                                 , p_st_conn_stat->dst_port
                                                                 , i_total_conn
                                                                 , p_st_conn_stat->ul_refused
                                                                 , p_st_conn_stat->ul_reset
                                                                 , p_st_conn_stat->ul_tx_bytes
                                                                 , p_st_conn_stat->ul_rx_bytes);
                    frreport_data_add_body(p_st_report_data, p_st_report_body);
                    i_has_report_data = FR_YES;
                }

                if( (p_st_conn_stat->ul_active == 0 && p_st_conn_stat->ul_tx_bytes==0 && p_st_conn_stat->ul_rx_bytes == 0)
                   && (p_st_conn_stat->l_uptime != 0 && l_uptime && l_uptime - p_st_conn_stat->l_uptime > FRSTAT_TIMEOUT_SEC) )
                {
                    p_st_node_del = frlist_node_create(p_st_node_stat);
                    if(p_st_node_del)
                        frlist_push(&st_lst_hdr_del, p_st_node_del);
                }
                if(l_uptime )
                    p_st_conn_stat->l_uptime = l_uptime;

                __sync_lock_release(&p_st_conn_stat->ul_syn);
                __sync_lock_release(&p_st_conn_stat->ul_close);
                __sync_lock_release(&p_st_conn_stat->ul_refused);
                __sync_lock_release(&p_st_conn_stat->ul_reset);
                __sync_lock_release(&p_st_conn_stat->ul_tx_bytes);
                __sync_lock_release(&p_st_conn_stat->ul_rx_bytes);
            }
            p_st_node_stat = FRLIST_NEXT_NODE(p_st_node_stat);
        }
    }
    if(i_has_report_data == FR_YES)
    {
        //FRLOG_DEBUG("stat_conn frreport_mng_save_report_data2");
        frreport_mng_save_report_data2(&p_st_report_data);
    }
    else
    {
        FRLOG_DEBUG("stat_conn no report");
        frreport_data_free(&p_st_report_data);
    }

    //删除空节点
    if(frlist_size(&st_lst_hdr_del) <=0)
        return;

    p_st_node_del = frlist_pop(&st_lst_hdr_del);
    while(p_st_node_del)
    {
        p_st_node_stat =  (Frlist_node*)FRLIST_GET_NODE_DATA(p_st_node_del);
        __frstat_conns_del(p_st_node_stat, l_uptime);
        frfree(p_st_node_del);
        p_st_node_del = frlist_pop(&st_lst_hdr_del);
    }

    return;
}

/*******************************************************************************
*  FUNC     :  增加连接数统计
*  ARGS     :  ui_src_ip        原ip
*           :  ui_dst_ip        目的ip
*           :  us_dst_port      目的port
*           :  i_conns          连接数据(增加:1，关闭:-1)
*  RTN      :  FR_SUCC   (成功)
*              FR_FAIL   (失败)
*  NOTE     :  
*******************************************************************************/
FR_STATIC int __frstat_conns_add_conn(u_int ui_src_ip, u_int ui_dst_ip, u_short us_dst_port
                                  , int i_conns, unsigned int ui_tx_bytes, unsigned int ui_rx_bytes)
{
    Frlist_node *p_st_node = NULL;
    Frlist_node *p_st_new_node = NULL;
    Frconns_stat *p_st_conn_stat=NULL;
    char arr_key[20];
    int i_key_len=0;
    
    i_key_len = __conn_key(ui_src_ip, ui_dst_ip, us_dst_port, arr_key, sizeof(arr_key));
    if(i_key_len <=0)
        return FR_FAIL;

    pthread_rwlock_wrlock(&g_conns_rwlock);
    p_st_node = frhash2_getStr(&g_st_hash_stat_conn, arr_key, i_key_len);
    if (p_st_node && p_st_node->data)
    {
        p_st_conn_stat = (Frconns_stat *)p_st_node->data;

    //if(i_conns)
    //{
    //    char arr_buff[128];
    //    frl4_print2(arr_buff, sizeof(arr_buff), 0, ui_src_ip, 0, ui_dst_ip, us_dst_port);
    //    FRLOG_ERROR_DETAIL("%s conn=%d active=%d",arr_buff, i_conns, p_st_conn_stat->ul_active);
    //}

        __sync_fetch_and_add(&p_st_conn_stat->ul_active, i_conns);
        if(i_conns > 0)
            __sync_fetch_and_add(&p_st_conn_stat->ul_syn, i_conns);
        if(i_conns < 0)
            __sync_fetch_and_add(&p_st_conn_stat->ul_close, -i_conns);
        if(ui_tx_bytes > 0)
            __sync_fetch_and_add(&p_st_conn_stat->ul_tx_bytes, ui_tx_bytes);
        if(ui_rx_bytes > 0)
            __sync_fetch_and_add(&p_st_conn_stat->ul_rx_bytes, ui_rx_bytes);
        pthread_rwlock_unlock(&g_conns_rwlock);
        return FR_SUCC;
    }

    //{
    //    char arr_buff[128];
    //    frl4_print2(arr_buff, sizeof(arr_buff), 0, ui_src_ip, 0, ui_dst_ip, us_dst_port);
    //    FRLOG_ERROR_DETAIL("%s conn=%d active=0",arr_buff, i_conns);
    //}

    //不应该出现该情况
    if(i_conns < 0)
    {
        char arr_buff[128];
        pthread_rwlock_unlock(&g_conns_rwlock);
        frl4_print2(arr_buff, sizeof(arr_buff), 0, ui_src_ip, 0, ui_dst_ip, us_dst_port);
        FRLOG_ERROR_DETAIL("err: %s conns < 0", arr_buff);
        return FR_FAIL;
    }

    p_st_conn_stat = (Frconns_stat *)frmalloc(sizeof(Frconns_stat));
    if (p_st_conn_stat == NULL)
    {
        pthread_rwlock_unlock(&g_conns_rwlock);
        FRLOG_ERROR_DETAIL("frmalloc err");
        return FR_FAIL;
    }
    memset(p_st_conn_stat, 0x00, sizeof(Frconns_stat));
    
    p_st_conn_stat->src_ip = ui_src_ip;
    p_st_conn_stat->dst_ip = ui_dst_ip;
    p_st_conn_stat->dst_port = us_dst_port;
    __sync_fetch_and_add(&p_st_conn_stat->ul_active, i_conns);
    if(i_conns > 0)
        __sync_fetch_and_add(&p_st_conn_stat->ul_syn, i_conns);
    if(i_conns < 0)
        __sync_fetch_and_add(&p_st_conn_stat->ul_close, -i_conns);
    if(ui_tx_bytes > 0)
        __sync_fetch_and_add(&p_st_conn_stat->ul_tx_bytes, ui_tx_bytes);
    if(ui_rx_bytes > 0)
        __sync_fetch_and_add(&p_st_conn_stat->ul_rx_bytes, ui_rx_bytes);
    
    p_st_new_node = frlist_node_create(p_st_conn_stat);
    if (p_st_new_node == NULL)
    {
        frfree(p_st_conn_stat);
        pthread_rwlock_unlock(&g_conns_rwlock);
        FRLOG_ERROR_DETAIL("frlist_node_create err");
        return FR_FAIL;
    }
    
    frhash2_addStr(&g_st_hash_stat_conn, arr_key, i_key_len, p_st_new_node);
    pthread_rwlock_unlock(&g_conns_rwlock);
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  增加包数量
*  ARGS     :  p_st_ct          Conntrack *
*           :  ui_tx_bytes      tx
*           :  ui_rx_bytes      rx
*  RTN      :  FR_SUCC   (成功)
*              FR_FAIL   (失败)
*  NOTE     :
*******************************************************************************/
int frstat_conns_add_traffic(Conntrack *p_st_ct, unsigned int ui_tx_bytes, unsigned int ui_rx_bytes)
{
    if(p_st_ct == NULL)
        return FR_FAIL;

    return __frstat_conns_add_conn(p_st_ct->report_src_ip, p_st_ct->report_dst_ip, p_st_ct->report_dst_port, 0, ui_tx_bytes, ui_rx_bytes);
}

/*******************************************************************************
*  FUNC     :  增加连接数统计
*  ARGS     :  p_st_ct                Conntrack *
*           :  flg_report_conn_info   连接上报标识  FR_YES:已上报 FR_NO:未上报
*           :  ui_src_ip        原ip
*           :  ui_dst_ip        目的ip
*           :  us_dst_port      目的port
*           :  i_conns          连接数据(增加:1，关闭:-1)
*  RTN      :  FR_SUCC   (成功)
*              FR_FAIL   (失败)
*  NOTE     :  需要注意多线程问题
*******************************************************************************/
int frstat_conns_add_conn_ct(Conntrack *p_st_ct, int flg_report_conn_info
                           , u_int ui_src_ip, u_int ui_dst_ip, u_short us_dst_port
                           , int i_conns, unsigned int ui_tx_bytes, unsigned int ui_rx_bytes)
{
    int i_ret_fun=0;

    if(p_st_ct == NULL)
        return FR_FAIL;

    if(i_conns)
    {
        //取消原来的连接
        if(p_st_ct->flg_report_conn_info == FR_YES && flg_report_conn_info == FR_YES
           && (p_st_ct->report_src_ip != ui_src_ip || p_st_ct->report_dst_ip != ui_dst_ip || p_st_ct->report_dst_port != us_dst_port) )
        {
            __frstat_conns_add_conn(p_st_ct->report_src_ip, p_st_ct->report_dst_ip, p_st_ct->report_dst_port, -1, 0, 0);
        }

        i_ret_fun = FR_FAIL;
        if(p_st_ct->flg_report_conn_info == FR_NO)
            i_ret_fun = __frstat_conns_add_conn(ui_src_ip, ui_dst_ip, us_dst_port, i_conns, ui_tx_bytes, ui_rx_bytes);
        else if( p_st_ct->flg_report_conn_info == FR_YES )
            if(i_conns > 0 )
            {
                if (p_st_ct->report_src_ip != ui_src_ip || p_st_ct->report_dst_ip != ui_dst_ip || p_st_ct->report_dst_port != us_dst_port)
                    i_ret_fun = __frstat_conns_add_conn(ui_src_ip, ui_dst_ip, us_dst_port, i_conns, ui_tx_bytes, ui_rx_bytes);
                else
                    i_ret_fun = __frstat_conns_add_conn(ui_src_ip, ui_dst_ip, us_dst_port, 0, ui_tx_bytes, ui_rx_bytes);
            }
            else
                i_ret_fun = __frstat_conns_add_conn(ui_src_ip, ui_dst_ip, us_dst_port, i_conns, ui_tx_bytes, ui_rx_bytes);
        else
            return FR_FAIL;

        if(i_ret_fun == FR_FAIL)
            return FR_FAIL;

        if(flg_report_conn_info == FR_YES)
        {
            p_st_ct->report_src_ip = ui_src_ip;
            p_st_ct->report_dst_ip = ui_dst_ip;
            p_st_ct->report_dst_port = us_dst_port;
        }
        else
        {
            p_st_ct->report_src_ip = 0;
            p_st_ct->report_dst_ip = 0;
            p_st_ct->report_dst_port = 0;
        }
        p_st_ct->flg_report_conn_info = flg_report_conn_info;

        return FR_SUCC;
    }

    //没有连接数据操作
    return __frstat_conns_add_conn(ui_src_ip, ui_dst_ip, us_dst_port, i_conns, ui_tx_bytes, ui_rx_bytes);
}

/*******************************************************************************
*  FUNC     :  增加连接数统计
*  ARGS     :  p_st_ct                Conntrack *
*           :  flg_report_conn_info   连接上报标识  FR_YES:已上报 FR_NO:未上报
*  RTN      :  FR_SUCC   (成功)
*              FR_FAIL   (失败)
*  NOTE     :  需要注意多线程问题
*******************************************************************************/
int frstat_conns_del_conn_ct(Conntrack *p_st_ct, int flg_report_conn_info)
{
    if(p_st_ct == NULL)
        return FR_FAIL;

    p_st_ct->flg_report_conn_info = flg_report_conn_info;
    return __frstat_conns_add_conn(p_st_ct->report_src_ip, p_st_ct->report_dst_ip, p_st_ct->report_dst_port, -1, 0, 0);
}

/*******************************************************************************
*  FUNC     :  统计 refused reset
*  ARGS     :  ui_src_ip        原ip
*           :  ui_dst_ip        目的ip
*           :  us_dst_port      目的port
*           :  em_type          操作类型
*           :  ui_data          操作数据
*  RTN      :  FR_SUCC   (成功)
*              FR_FAIL   (失败)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frstat_conns_add_refued_reset(u_int ui_src_ip, u_int ui_dst_ip, u_short us_dst_port
                                           ,  unsigned int ui_refuse, unsigned int ui_reset)
{
    Frlist_node *p_st_node = NULL;
    Frlist_node *p_st_new_node = NULL;
    Frconns_stat *p_st_conn_stat=NULL;
    char arr_key[20];
    int i_key_len=0;

    if(ui_refuse == 0 && ui_reset == 0)
        return FR_FAIL;

    i_key_len = __conn_key(ui_src_ip, ui_dst_ip, us_dst_port, arr_key, sizeof(arr_key));
    if(i_key_len <=0)
        return FR_FAIL;

    pthread_rwlock_wrlock(&g_conns_rwlock);
    p_st_node = frhash2_getStr(&g_st_hash_stat_conn, arr_key, i_key_len);
    if (p_st_node && p_st_node->data)
    {
        p_st_conn_stat = (Frconns_stat *)p_st_node->data;
        if(ui_refuse > 0 )
            __sync_fetch_and_add(&p_st_conn_stat->ul_refused, ui_refuse);
        if(ui_reset > 0)
            __sync_fetch_and_add(&p_st_conn_stat->ul_reset, ui_reset);

        pthread_rwlock_unlock(&g_conns_rwlock);
        return FR_SUCC;
    }

    p_st_conn_stat = (Frconns_stat *) frmalloc(sizeof(Frconns_stat));
    if (p_st_conn_stat == NULL)
    {
        pthread_rwlock_unlock(&g_conns_rwlock);
        FRLOG_ERROR_DETAIL("frmalloc err");
        return FR_FAIL;
    }
    memset(p_st_conn_stat, 0x00, sizeof(Frconns_stat));

    p_st_conn_stat->src_ip = ui_src_ip;
    p_st_conn_stat->dst_ip = ui_dst_ip;
    p_st_conn_stat->dst_port = us_dst_port;
    if(ui_refuse > 0 )
        __sync_fetch_and_add(&p_st_conn_stat->ul_refused, ui_refuse);
    if(ui_reset > 0)
        __sync_fetch_and_add(&p_st_conn_stat->ul_reset, ui_reset);

    p_st_new_node = frlist_node_create(p_st_conn_stat);
    if (p_st_new_node == NULL)
    {
        frfree(p_st_conn_stat);
        pthread_rwlock_unlock(&g_conns_rwlock);
        FRLOG_ERROR_DETAIL("frlist_node_create err");
        return FR_FAIL;
    }

    frhash2_addStr(&g_st_hash_stat_conn, arr_key, i_key_len, p_st_new_node);
    pthread_rwlock_unlock(&g_conns_rwlock);
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  拒绝连接数统计
*  ARGS     :  ui_src_ip        原ip
*           :  ui_dst_ip        目的ip
*           :  us_dst_port      目的port
*           :  ui_refuses       拒绝连接数
*  RTN      :  FR_SUCC   (成功)
*              FR_FAIL   (失败)
*  NOTE     :
*******************************************************************************/
int frstat_conns_add_refused(u_int ui_src_ip, u_int ui_dst_ip, u_short us_dst_port, unsigned int ui_refuses)
{
    return __frstat_conns_add_refued_reset(ui_src_ip, ui_dst_ip, us_dst_port, ui_refuses, 0);
}

/*******************************************************************************
*  FUNC     :  reset连接数统计
*  ARGS     :  ui_src_ip        原ip
*           :  ui_dst_ip        目的ip
*           :  us_dst_port      目的port
*           :  ui_reset         reset连接数
*  RTN      :  FR_SUCC   (成功)
*              FR_FAIL   (失败)
*  NOTE     :
*******************************************************************************/
int frstat_conns_add_reset(u_int ui_src_ip, u_int ui_dst_ip, u_short us_dst_port, unsigned int ui_reset)
{
    return __frstat_conns_add_refued_reset(ui_src_ip, ui_dst_ip, us_dst_port, 0, ui_reset);
}

/*******************************************************************************
*  FUNC     :  统计信息操作公用函数
*  ARGS     :  ui_src_ip        原ip
*           :  ui_dst_ip        目的ip
*           :  us_dst_port      目的port
*           :  em_type          操作类型
*           :  ui_data          操作数据
*  RTN      :  FR_SUCC   (成功)
*              FR_FAIL   (失败)
*  NOTE     :
*******************************************************************************/
//FR_STATIC int __frstat_conns_add(u_int ui_src_ip, u_int ui_dst_ip, u_short us_dst_port, Frstat_conn_type em_type, unsigned int ui_data)
//{
//    Frlist_node *p_st_node = NULL;
//    Frconns_stat *p_st_conn_stat=NULL;
//    char arr_key[20];
//    int i_key_len=0;
//
//    i_key_len = __conn_key(ui_src_ip, ui_dst_ip, us_dst_port, arr_key, sizeof(arr_key));
//    if(i_key_len <=0)
//        return FR_FAIL;
//
//    pthread_rwlock_wrlock(&g_conns_rwlock);
//    p_st_node = frhash2_getStr(&g_st_hash_stat_conn, arr_key, i_key_len);
//    if (p_st_node && p_st_node->data)
//    {
//        p_st_conn_stat = (Frconns_stat *)p_st_node->data;
//        switch(em_type)
//        {
//            case FRSTAT_CONN_TYPE_TX:
//                __sync_fetch_and_add(&p_st_conn_stat->ul_tx_bytes, ui_data);
//                break;
//            case FRSTAT_CONN_TYPE_RX:
//                __sync_fetch_and_add(&p_st_conn_stat->ul_rx_bytes, ui_data);
//                break;
//            default:
//                break;
//        }
//
//        pthread_rwlock_unlock(&g_conns_rwlock);
//        return FR_SUCC;
//    }
//    pthread_rwlock_unlock(&g_conns_rwlock);
//
//    return FR_FAIL;
//}
//
//
//
///*******************************************************************************
//*  FUNC     :  tx_bytes数统计
//*  ARGS     :  ui_src_ip        原ip
//*           :  ui_dst_ip        目的ip
//*           :  us_dst_port      目的port
//*           :  ui_tx_bytes      发送数据包bytes
//*  RTN      :  FR_SUCC   (成功)
//*              FR_FAIL   (失败)
//*  NOTE     :
//*******************************************************************************/
//int frstat_conns_add_tx_bytes(u_int ui_src_ip, u_int ui_dst_ip, u_short us_dst_port, unsigned int ui_tx_bytes)
//{
//    return __frstat_conns_add(ui_src_ip, ui_dst_ip, us_dst_port, FRSTAT_CONN_TYPE_TX, ui_tx_bytes);
//}
//
///*******************************************************************************
//*  FUNC     :  rx_bytes数统计
//*  ARGS     :  ui_src_ip        原ip
//*           :  ui_dst_ip        目的ip
//*           :  us_dst_port      目的port
//*           :  ui_rx_bytes      接受数据包bytes
//*  RTN      :  FR_SUCC   (成功)
//*              FR_FAIL   (失败)
//*  NOTE     :
//*******************************************************************************/
//int frstat_conns_add_rx_bytes(u_int ui_src_ip, u_int ui_dst_ip, u_short us_dst_port, unsigned int ui_rx_bytes)
//{
//    return __frstat_conns_add(ui_src_ip, ui_dst_ip, us_dst_port, FRSTAT_CONN_TYPE_RX, ui_rx_bytes);
//}

/*******************************************************************************
*  FUNC     :  初始化连接数统计
*  ARGS     :  
*  RTN      :  FR_SUCC   (成功)
*              FR_FAIL   (失败)
*  NOTE     :  
*******************************************************************************/
int frstat_conns_init(unsigned long ul_hash_size)
{
    if (pthread_rwlock_init(&g_conns_rwlock, NULL) != 0)
    {
        FRLOG_ERROR_DETAIL("pthread_rwlock_init failed");
        return FR_FAIL;
    }

    if (frhash2_create(&g_st_hash_stat_conn, ul_hash_size) != FR_SUCC)
    {
        FRLOG_ERROR_DETAIL("frhash2_create failed");
        pthread_rwlock_destroy(&g_conns_rwlock);
        return FR_FAIL;
    }

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  退出连接数统计
*  ARGS     :  
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
void frstat_conns_destroy(void)
{
    pthread_rwlock_wrlock(&g_conns_rwlock);
    frhash2_free(&g_st_hash_stat_conn, frlist_node_data_free);
    pthread_rwlock_unlock(&g_conns_rwlock);
    
    pthread_rwlock_destroy(&g_conns_rwlock);

    return;
}
